package com.lipaluma.field.merge;

import java.lang.reflect.Array;
import java.util.Collection;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import com.lipaluma.exceptions.CsvParserProcessException;

/**
 * Different strategies of merging by value.
 * @author Mario
 */
public enum FieldMergedAlgorithmEnum implements FieldMergedAlgorithm {
	/**
	 * Merge 2 collections by putting the elements of the newObject to the oldObject
	 */
	ADD_ALL {
		@SuppressWarnings("unchecked")
		public Object merge(Object oldObject, Object newObject, String... params) {
			if(oldObject.getClass().isArray()) {
				int size1 = Array.getLength(oldObject);
				int size2 = Array.getLength(newObject);
				Object[] result = new Object[size1+size2];
				System.arraycopy(oldObject, 0, result, 0, size1);
				System.arraycopy(newObject, 0, result, size1, size2);
				return result;
			} else if (Collection.class.isAssignableFrom(oldObject.getClass())) {
				((Collection<Object>)oldObject).addAll((Collection<Object>)newObject);
				return oldObject;
			}
			throw new CsvParserProcessException("The fusion ADD_ALL is not managed with type "+oldObject.getClass());
		}
		
		@SuppressWarnings("unchecked")
		public Object[] unmerge(Object value) {
			Collection<Object> values = (Collection<Object>)value;
			return values.toArray();
		}
	/**
	 * return the newObject and ignore the old
	 */
	}, REPLACE {
		public Object merge(Object oldObject, Object newObject, String... params) {
			return newObject;
		}
		
		public Object[] unmerge(Object value) {
			return new Object[]{value};
		}
	/**
	 * values must be String types. <br>
	 * It will concatenate the oldObject with the new
	 */
	}, CONCAT {
		public Object merge(Object oldObject, Object newObject, String... params) {
			String separator = "";
			if(ArrayUtils.isNotEmpty(params))
				separator = params[0];
			try {
				String oldString = (String)oldObject;
				String newString = (String)newObject;
				return new StringBuilder(oldString).append(separator).append(newString);
			} catch (ClassCastException e) {
				throw new CsvParserProcessException("Error in Concat Merge strategy. Values must be String types", e);
			}
		}
		public Object[] unmerge(Object value) {
			if(StringUtils.isBlank((String)value))
					return new Object[]{};
			return StringUtils.splitPreserveAllTokens((String)value);
		}
	};
}
